Imports System.ComponentModel
Imports System.Configuration.Install
Imports System.IO
Imports System.Data.SqlClient


<RunInstaller(True)> Public Class MIMSInstaller
    Inherits System.Configuration.Install.Installer

#Region " Component Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Component Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Installer overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Component Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Component Designer
    'It can be modified using the Component Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        components = New System.ComponentModel.Container()
    End Sub

#End Region
    Private APPLICATION_ROOT_KEY As String = "AppRoot"
    Private CONNECTION_STRING_KEY As String = "ConnectionString"
    Private TABLE_SCRIPT_DIR_PATH As String = "\DBScripts\TB"
    Private SP_SCRIPT_DIR_PATH As String = "\DBScripts\SP"
    Private INIT_SCRIPT_DIR_PATH As String = "\DBScripts\INIT"

#Region "   Properties"
    Private ReadOnly Property DBOption() As Integer
        Get
            Return CInt(Me.Context.Parameters.Item("DBOption"))
        End Get
    End Property

    Private ReadOnly Property DBName() As String
        Get
            Return Me.Context.Parameters.Item("DBName")
        End Get
    End Property

    Private ReadOnly Property ServerName() As String
        Get
            Return Me.Context.Parameters.Item("ServerName")
        End Get
    End Property

    Private ReadOnly Property UserUsername() As String
        Get
            Return Me.Context.Parameters.Item("UserUsername")
        End Get
    End Property

    Private ReadOnly Property UserPassword() As String
        Get
            Return Me.Context.Parameters.Item("UserPassword")
        End Get
    End Property

    Private ReadOnly Property AdminUsername() As String
        Get
            Return Me.Context.Parameters.Item("AdminUsername")
        End Get
    End Property

    Private ReadOnly Property AdminPassword() As String
        Get
            Return Me.Context.Parameters.Item("AdminPassword")
        End Get
    End Property

    Private ReadOnly Property WrsAdminUsername() As String
        Get
            Return Me.Context.Parameters.Item("WrsAdminUsername")
        End Get
    End Property

    Private ReadOnly Property WrsAdminName() As String
        Get
            Return Me.Context.Parameters.Item("WrsAdminName")
        End Get
    End Property

    Private ReadOnly Property WrsAdminPassword() As String
        Get
            Return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(Me.Context.Parameters.Item("WrsAdminPassword"), "md5")
        End Get
    End Property

    Private ReadOnly Property WrsAdminEmail() As String
        Get
            Return Me.Context.Parameters.Item("WrsAdminEmail")
        End Get
    End Property

    Private ReadOnly Property VirtualDirectory() As String
        Get
            Return Me.Context.Parameters.Item("TargetVDir")
        End Get
    End Property

    Private ReadOnly Property AdminConnectionString() As String
        Get
            Return String.Format("server={0};uid={1};pwd={2};database={3};pooling=false", Me.ServerName, Me.AdminUsername, Me.AdminPassword, "master")
        End Get
    End Property

    Private ReadOnly Property AdminConnectionStringForDB() As String
        Get
            Return String.Format("server={0};uid={1};pwd={2};database={3};pooling=false", Me.ServerName, Me.AdminUsername, Me.AdminPassword, Me.DBName)
        End Get
    End Property

    Private ReadOnly Property UserConnectionString() As String
        Get
            Return String.Format("server={0};uid={1};pwd={2};database={3};", Me.ServerName, Me.UserUsername, Me.UserPassword, Me.DBName)
        End Get
    End Property

    Private Property ProgressLabel() As String
        Get
            Return Me.Context.Parameters.Item("ProgressLabel")
        End Get
        Set(ByVal Value As String)
            Me.Context.Parameters.Item("ProgressLabel") = Value
        End Set
    End Property


#End Region

#Region "   SQL related functions"
    ' Get SQL script from a file
    Private Function GetSql(ByVal filePath As String) As String
        Try
            Dim reader As StreamReader = New StreamReader(filePath)
            Return reader.ReadToEnd()
        Catch ex As Exception
            MsgBox("In GetSQL: " & ex.Message)
            Throw ex
        End Try
    End Function

    Private Sub RunScriptFromDirectory(ByVal dirPath As String, ByVal conn As SqlConnection)
        Dim d As New DirectoryInfo(dirPath)
        Dim fis() As FileInfo = d.GetFiles()
        Dim fi As FileInfo
        For Each fi In fis
            Me.ProgressLabel = "Installing: " & fi.Name
            ExecuteSql(conn, GetSql(fi.FullName))
        Next
    End Sub

    Private Sub ExecuteSql(ByVal connectionString As String, ByVal Sql As String)

        Dim conn As New SqlClient.SqlConnection

        conn.ConnectionString = connectionString

        Dim Command As New SqlClient.SqlCommand(Sql, conn)

        Command.Connection.Open()
        'Command.Connection.ChangeDatabase(DatabaseName)
        Try
            Command.CommandText = "SET ANSI_NULLS OFF"
            Command.ExecuteNonQuery()
            Command.CommandText = Sql
            Command.ExecuteNonQuery()
            Command.CommandText = "SET ANSI_NULLS ON"
            Command.ExecuteNonQuery()
        Finally
            ' Finally, blocks are a great way to ensure that the connection 
            ' is always closed.
            Command.Connection.Close()
        End Try

    End Sub

    Private Sub ExecuteSql(ByVal connection As SqlConnection, ByVal Sql As String)
        Dim Command As New SqlClient.SqlCommand(Sql, connection)

        Command.CommandText = "SET ANSI_NULLS OFF"
        Command.ExecuteNonQuery()
        Command.CommandText = Sql
        Command.ExecuteNonQuery()
        Command.CommandText = "SET ANSI_NULLS ON"
        Command.ExecuteNonQuery()
    End Sub

#End Region

    Private Sub CreateNewDB()
        Try
            ExecuteSql(Me.AdminConnectionString, "CREATE DATABASE " & Me.DBName)
        Catch ex As Exception
            MsgBox("In CreateNewDB : " & ex.Message)
            Throw ex
        End Try        
    End Sub

    Private Sub CreateTablesAndSP(ByVal appDir As String, ByVal connectionString As String)
        Dim conn As New SqlConnection(connectionString)
        SyncLock GetType(MIMSInstaller)
            Try
                conn.Open()

                Me.RunScriptFromDirectory(appDir & Me.TABLE_SCRIPT_DIR_PATH, conn)


                Me.RunScriptFromDirectory(appDir & Me.SP_SCRIPT_DIR_PATH, conn)

                Me.RunScriptFromDirectory(appDir & Me.INIT_SCRIPT_DIR_PATH, conn)


                'insert admin user
                Me.ExecuteSql(conn, String.Format("exec UserInsertCommand '{0}', '{1}', '{2}', '{3}', 1, 'United States', NULL, NULL, 1, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL", Me.WrsAdminName, Me.WrsAdminUsername, Me.WrsAdminPassword, Me.WrsAdminEmail))


                If conn.State <> ConnectionState.Closed Then
                    conn.Close()
                    conn.Dispose()
                End If
            Catch ex As Exception
                MsgBox("In CreateTablesAndSP : " & ex.Message)
                If conn.State <> ConnectionState.Closed Then
                    conn.Close()
                    conn.Dispose()
                End If
                Throw ex
            End Try
        End SyncLock

    End Sub

    Private Sub ModifyWebConfig(ByVal rootPath As String, ByVal rootDir As String, ByVal connectionString As String)

        'check for file exists
        Dim FileInfo As System.IO.FileInfo = New System.IO.FileInfo(rootPath & "\web.config")
        If Not FileInfo.Exists Then
            Throw New InstallException("Missing config file")
        End If

        ' Load the config file into the XML DOM.
        Dim XmlDocument As New System.Xml.XmlDocument
        XmlDocument.Load(FileInfo.FullName)

        ' Find the right node and change it to the new value.
        Dim Node As System.Xml.XmlNode
        Dim FoundIt As Boolean = False
        For Each Node In XmlDocument.Item("configuration").Item("appSettings")
            If Node.Name = "add" Then ' skip any comments
                Select Case Node.Attributes.GetNamedItem("key").Value
                    Case Me.APPLICATION_ROOT_KEY
                        Node.Attributes.GetNamedItem("value").Value = "/" & rootDir
                    Case Me.CONNECTION_STRING_KEY
                        Node.Attributes.GetNamedItem("value").Value = connectionString
                        FoundIt = True
                End Select
            End If
        Next Node

        If Not FoundIt Then
            Throw New InstallException("Config file did not contain a ConnectionString section")
        End If

        ' Write out the new config file.
        XmlDocument.Save(FileInfo.FullName)

    End Sub

    Public Overrides Sub Install(ByVal stateSaver As System.Collections.IDictionary)

        MyBase.Install(stateSaver)

        Dim appDir As String

        ' Get directory where assembly has just been installed from the assembly information
        Dim Asm As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly
        Dim fiTemp As System.IO.FileInfo = New System.IO.FileInfo(Asm.Location)
        appDir = fiTemp.Directory.Parent.FullName

        'MsgBox(Me.WrsAdminEmail & Me.WrsAdminName & Me.WrsAdminPassword & Me.WrsAdminUsername)
        Select Case DBOption
            Case 1  'create new
                CreateNewDB()
                ' running script file series
                CreateTablesAndSP(appDir, Me.AdminConnectionStringForDB)
            Case 2  ' use existing
                ' running script file series
                CreateTablesAndSP(appDir, Me.UserConnectionString)
            Case 3  ' none
        End Select

        ModifyWebConfig(appDir, Me.VirtualDirectory, Me.UserConnectionString)

    End Sub

    Public Overrides Sub Rollback(ByVal savedState As System.Collections.IDictionary)
        MyBase.Rollback(savedState)

        If Me.DBOption = 1 Then
            Try
                Me.ExecuteSql(Me.AdminConnectionString, "DROP DATABASE " & Me.DBName)
            Catch ex As Exception

            End Try
        End If
    End Sub

End Class
